import json
import logging

import numpy as np

from api import utils
from api.serial import figure, sample
from api.serial.analyse import get_every_seg_for_positive_portrait_v2

logger = logging.getLogger('serial.sample')


# zxy 修改于 20200112
def detect_sample(sample, portrait, cal_seg=True, isPostive=True):
    '''
    :param sample: 样本数据
    :param portrait: 画像
    :param cal_seg: 是否分段

    :param isPostive: 画像是否是正样本画像
    :return: 检测结果
    '''

    detect_count = min(len(portrait.actual_pressure),
                       len(portrait.actual_location),
                       len(portrait.actual_speed))
    sample_length = min(len(sample.actual_pressure),
                        len(sample.actual_location),
                        len(sample.actual_speed))
    if sample_length < detect_count:  # 如果待检测样本长度小于画像长度，则调整画像长度
        detect_count = sample_length
        temp_figure = figure.FigureResult(None)
        temp_figure = fill_temp_figure(detect_count, temp_figure, portrait)  # 返回一个temp_figure
        portrait = temp_figure

    if isPostive:
        # 计算马氏距离
        sample.cal_total_madis(detect_count, portrait.feature, portrait.feature_var)
        # 计算高斯分布下, 样本距离平均值的sigma倍数
        sample.cal_total_madis_times(portrait.dist_total_mean, portrait.dist_total_var)
        if cal_seg:
            # 正样本画像分段的后各段的索引,长度,特征向量，特征向量方差
            _, len_seg_list, feat_seg_list, feat_var_seg_list = portrait.each_seg
            # 计算该样本在每一段的马氏距离
            sample.cal_segs_madis(len_seg_list, feat_seg_list, feat_var_seg_list)
            # 计算该样本在每一段与正样本画像的时间差
            sample.cal_segs_time_diff(portrait.seg_points)
            # 根据正样本画像每一段的马氏距离平均值，方差, 时间差距平均值,方差计算该样本各段的置信度
            sample.get_segs_rate(portrait.dist_means, portrait.dist_vars, portrait.td_means,
                                 portrait.td_vars)
        # 保留两位小数
        sample.round_for_ui()
        # 各段置信度, 实际压力, 螺杆位置, 速度, 分段点, 总体置信度, 设定压力,各段的马氏距离,总体的马氏距离
        return [sample.seg_rate_list, sample.actual_pressure, sample.actual_location,
                sample.actual_speed, sample.seg_points,
                sample.total_rate, sample.setting_pressure, sample.seg_madis_list, sample.total_madis]

    # 检测与负样本画像的异常率
    # zxy 修改于 20200112
    else:
        # 计算马氏距离
        sample.cal_total_madis(detect_count, portrait.feature, portrait.feature_var)
        # 计算高斯分布下的总异常率*
        sample.cal_total_rate(portrait.dist_total_mean, portrait.dist_total_var)
        return sample.total_rate


# 如果画像的长度大于待测样本的长度,则需要将画像长度降到跟样本长度一样
def fill_temp_figure(detect_count, temp_figure, portrait):
    temp_figure.length = detect_count
    temp_figure.actual_pressure = np.array(portrait.actual_pressure[:detect_count])
    temp_figure.actual_location = np.array(portrait.actual_location[:detect_count])
    temp_figure.actual_speed = np.array(portrait.actual_speed[:detect_count])
    temp_figure.setting_pressure = np.array(portrait.setting_pressure[:detect_count])
    temp_figure.sample_count = portrait.get_sample_count()
    temp_figure.length = portrait.length
    temp_figure.pressure_var = np.array(portrait.pressure_var[:detect_count])
    temp_figure.location_var = np.array(portrait.location_var[:detect_count])
    temp_figure.speed_var = np.array(portrait.speed_var[:detect_count])
    sample_index = np.array(list(range(0, detect_count, 8))).astype('int32')
    temp_figure.feature = np.concatenate(
        [temp_figure.actual_pressure[sample_index], temp_figure.actual_location[sample_index],
         temp_figure.actual_speed[sample_index]]).tolist()
    temp_figure.feature_var = np.concatenate(
        [temp_figure.pressure_var[sample_index], temp_figure.location_var[sample_index],
         temp_figure.speed_var[sample_index]]).tolist()

    temp_figure.dist_total_mean, temp_figure.dist_total_var = portrait.dist_total_mean, portrait.dist_total_var
    temp_figure.dist_means, temp_figure.dist_vars, temp_figure.td_means, temp_figure.td_vars \
        = portrait.dist_means, portrait.dist_vars, portrait.td_means, portrait.td_vars
    # 根据实际压力和设定压力进行分段
    try:
        seg_points = sample.ProductSample.curve_segmentation(temp_figure.actual_pressure, temp_figure.setting_pressure)
    except Exception as e:
        logger.error(f'正样本画像分段失败,{e}')
        raise e
    temp_figure.set_seg_points(seg_points)
    sample_index_seg_list, len_seg_list, portrait_feat_seg_list, feat_var_seg_list = [], [], [], []
    for i in range(len(seg_points) - 1):
        sample_index_seg, len_seg, portrait_feat_seg, feat_var_seg = \
            get_every_seg_for_positive_portrait_v2(detect_count, sample_index, seg_points[i],
                                                   seg_points[i + 1],
                                                   temp_figure.actual_pressure,
                                                   temp_figure.actual_location, temp_figure.actual_speed,
                                                   temp_figure.pressure_var,
                                                   temp_figure.location_var,
                                                   temp_figure.speed_var)
        sample_index_seg_list.append(sample_index_seg.tolist())
        len_seg_list.append(len_seg)
        portrait_feat_seg_list.append(portrait_feat_seg.tolist())
        feat_var_seg_list.append(feat_var_seg.tolist())
    # 存进采样分段后的正样本画像
    temp_figure.set_every_segs_info([sample_index_seg_list, len_seg_list, portrait_feat_seg_list, feat_var_seg_list])
    return temp_figure


# 弃用
def save_detect_result(detect_result, out_file):
    utils.check_dir_exist(out_file)
    json_str = json.dumps(detect_result, cls=sample.NpEncoder)
    with open(out_file, mode='a+') as writer:
        writer.write(json_str + '\n')


if __name__ == '__main__':
    pass
